package yhao.infra.feature.dubbo.filter.validation;

import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import yhao.infra.feature.dubbo.api.DubboResult;
import yhao.infra.feature.dubbo.api.ValidationArgs;

import java.util.HashMap;
import java.util.Map;

import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;

@Activate(group = PROVIDER, order = -30000)
public class ValidationFilter implements Filter {

    private final Class returnType = DubboResult.class;

    private Map<String,Class> typeMap = new HashMap<>();

    protected ValidationBean validationBean;

    public ValidationFilter(){
        validationBean = new ValidationBean();
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Object[] args = invocation.getArguments();
        if (args == null || args.length == 0) {
            return invoker.invoke(invocation);
        }
        for (Object arg : args) {
            if (arg instanceof ValidationArgs) {
                ValidationResult result = validationBean.validationParam((ValidationArgs) arg);
                if (result.hasError()) {
                    String method = invoker.getInterface().getName()+invocation.getMethodName();
                    Class type = typeMap.get(method);
                    if(type ==null){
                        try {
                            type = invoker.getInterface().getMethod(
                                    invocation.getMethodName(), invocation.getParameterTypes()).getReturnType();
                        } catch (Exception e) {
                            type = Void.class;
                        } finally {
                            typeMap.put(method,type);
                        }
                    }
                    if (returnType.equals(type)) {
                        DubboResult requestResult =
                                new DubboResult(false, null, result.getErrorMessages().get(0).getMessage());
                        return new AppResponse(requestResult);
                    }else{
                        throw new RpcException(result.getErrorMessages().get(0).getMessage());
                    }
                }
            }
        }
        return invoker.invoke(invocation);
    }
}
